#include "scene.hpp"
#include "view.hpp"
#include "light.hpp"

#include "GL/glew.h"
#include "GL/glut.h"
#include "GL/glu.h"

#include "objloader.h"
#include "objsaver.h"

#include <iostream>
#include <cmath>
#define PI 3.141593
#define EPS 0.000001

using namespace std;

ObjLoader testscene = ObjLoader("../obj/girl OBJ.obj");

Scene::Scene(){
    textures.registerTexture("./texture/skybox/left.png", "sky_l");
    textures.registerTexture("./texture/skybox/right.png", "sky_r");
    textures.registerTexture("./texture/skybox/front.png", "sky_f");
    textures.registerTexture("./texture/skybox/back.png", "sky_b");
    textures.registerTexture("./texture/skybox/up.png", "sky_u");
    textures.registerTexture("./texture/skybox/down.png", "sky_d");
    textures.registerTexture("./texture/wall_top.png", "wall_t");
    textures.registerTexture("./texture/wall_side.png", "wall_s");
    textures.registerTexture("./texture/outlet_side.png", "outlet_s");
    textures.registerTexture("./texture/outlet_stone.png", "outlet_stone");
    textures.registerTexture("./texture/outlet_snow.png", "outlet_snow");
    textures.registerTexture("./texture/outlet_bottom.png", "outlet_bottom");
    textures.registerTexture("./texture/box_type_a.png", "box_a");
    textures.registerTexture("./texture/box_type_b.png", "box_b");
    textures.registerTexture("./texture/box_type_c.png", "box_c");
    textures.registerTexture("./texture/conveyor_drum.png", "conv_drum");
    textures.registerTexture("./texture/conveyor_belt.png", "conv_belt");
    textures.registerTexture("./texture/conveyor_side_a.png", "conv_arrow");
    textures.registerTexture("./texture/conveyor_side_b.png", "conv_side");
    textures.registerTexture("./texture/conveyor_down.png", "conv_down");
    textures.registerTexture("./texture/dest_a_top_yes.png", "dest_a_yes");
    textures.registerTexture("./texture/dest_a_top_no.png", "dest_a_no");
    textures.registerTexture("./texture/dest_a_down.png", "dest_a_d");
    textures.registerTexture("./texture/dest_a_side.png", "dest_a_s");
    textures.registerTexture("./texture/dest_b_up.png", "dest_b_u");
    textures.registerTexture("./texture/dest_b_side.png", "dest_b_s");
    station_list.push_back(Station(18, 15, 0, 0));
    station_list.push_back(Station(-4, -20, 0, 1));
    station_list.push_back(Station(-12, -20, 0, 2));

    // test here
    box_list.push_back(Box(-4, -2, 4, 1));

    addConveyor(-4, 0, 2, 1);
    addConveyor(-4, -2, 2, 1);
    addConveyor(-4, -4, 2, 1);
    addConveyor(-4, -6, 2, 1);
    addConveyor(-4, -8, 0, 1);
    addConveyor(-4, -10, 0, 1);
    addConveyor(-4, -12, 0, 1);
    addConveyor(-4, -14, 0, 1);
    addConveyor(-4, -16, 0, 1);
    addConveyor(-4, -18, 0, 1);

    start();
}

void Scene::calcOutletTexCood(double pts_cood[4][3], double tex_cood[4][2]){
    for(int i = 0;i < 4;i++){
        tex_cood[i][0] = 1.0f*(pts_cood[i][0] + 3)/6.0f;
        tex_cood[i][1] = 1.0f*(pts_cood[i][2] + 3)/6.0f;
    }
}

void Scene::drawOutlet(int pos_x, int pos_y, int pos_z){
    glPushMatrix();
    glTranslatef(pos_x, pos_y, pos_z+1);

    double tex_cood[4][2];
    double side_tex_cood[4][2] = {{1, 1}, {1, 0}, {0, 0}, {0, 1}};
    
    double pts_front_a[4][3] = {{-3, 0, 3},
                                {-2, 0, 3},
                                {-2, 0, -3},
                                {-3, 0, -3}};
    calcOutletTexCood(pts_front_a, tex_cood);
    drawQuadFace("outlet_s", pts_front_a, tex_cood);

    double pts_front_b[4][3] = {{-2, 1, 2},
                                {-1, 1, 2},
                                {-1, 1, -2},
                                {-2, 1, -2}};
    calcOutletTexCood(pts_front_b, tex_cood);
    drawQuadFace("outlet_stone", pts_front_b, tex_cood);

    double pts_front_c[4][3] = {{1, 1, 2},
                                {2, 1, 2},
                                {2, 1, -2},
                                {1, 1, -2}};
    calcOutletTexCood(pts_front_c, tex_cood);
    drawQuadFace("outlet_stone", pts_front_c, tex_cood);

    double pts_front_d[4][3] = {{2, 0, 3},
                                {3, 0, 3},
                                {3, 0, -3},
                                {2, 0, -3}};
    calcOutletTexCood(pts_front_d, tex_cood);
    drawQuadFace("outlet_s", pts_front_d, tex_cood);

    double pts_front_e[4][3] = {{-2, 0, 3},
                                {2, 0, 3},
                                {2, 0, 2},
                                {-2, 0, 2}};
    calcOutletTexCood(pts_front_e, tex_cood);
    drawQuadFace("outlet_s", pts_front_e, tex_cood);

    double pts_front_f[4][3] = {{-1, 1, 2},
                                {1, 1, 2},
                                {1, 1, 1},
                                {-1, 1, 1}};
    calcOutletTexCood(pts_front_f, tex_cood);
    drawQuadFace("outlet_stone", pts_front_f, tex_cood);

    double pts_front_g[4][3] = {{-1, 1, -1},
                                {1, 1, -1},
                                {1, 1, -2},
                                {-1, 1, -2}};
    calcOutletTexCood(pts_front_g, tex_cood);
    drawQuadFace("outlet_stone", pts_front_g, tex_cood);

    double pts_front_h[4][3] = {{-2, 0, -2},
                                {2, 0, -2},
                                {2, 0, -3},
                                {-2, 0, -3}};
    calcOutletTexCood(pts_front_h, tex_cood);
    drawQuadFace("outlet_s", pts_front_h, tex_cood);

    double pts_inner_a[4][3] = {{-2, 0, 2},
                                {-2, 1, 2},
                                {-2, 1, -2},
                                {-2, 0, -2}};
    drawQuadFace("outlet_stone", pts_inner_a, side_tex_cood);

    double pts_inner_b[4][3] = {{2, 0, 2},
                                {2, 1, 2},
                                {2, 1, -2},
                                {2, 0, -2}};
    drawQuadFace("outlet_stone", pts_inner_b, side_tex_cood);

    double pts_inner_c[4][3] = {{-2, 0, -2},
                                {-2, 1, -2},
                                {2, 1, -2},
                                {2, 0, -2}};
    drawQuadFace("outlet_snow", pts_inner_c, side_tex_cood);

    double pts_inner_d[4][3] = {{-2, 0, 2},
                                {-2, 1, 2},
                                {2, 1, 2},
                                {2, 0, 2}};
    drawQuadFace("outlet_stone", pts_inner_d, side_tex_cood);

    double pts_inner_e[4][3] = {{-1, 1, 1},
                                {-1, 2, 1},
                                {-1, 2, -1},
                                {-1, 1, -1}};
    drawQuadFace("outlet_stone", pts_inner_e, side_tex_cood);

    double pts_inner_f[4][3] = {{1, 1, 1},
                                {1, 2, 1},
                                {1, 2, -1},
                                {1, 1, -1}};
    drawQuadFace("outlet_stone", pts_inner_f, side_tex_cood);

    double pts_inner_g[4][3] = {{-1, 1, -1},
                                {-1, 2, -1},
                                {1, 2, -1},
                                {1, 1, -1}};
    drawQuadFace("outlet_snow", pts_inner_g, side_tex_cood);

    double pts_inner_h[4][3] = {{-1, 1, 1},
                                {-1, 2, 1},
                                {1, 2, 1},
                                {1, 1, 1}};
    drawQuadFace("outlet_stone", pts_inner_h, side_tex_cood);

    double pts_outer_a[4][3] = {{-3, 0, 3},
                                {-3, 2, 3},
                                {-3, 2, -3},
                                {-3, 0, -3}};
    drawQuadFace("outlet_stone", pts_outer_a, side_tex_cood);

    double pts_outer_b[4][3] = {{3, 0, 3},
                                {3, 2, 3},
                                {3, 2, -3},
                                {3, 0, -3}};
    drawQuadFace("outlet_stone", pts_outer_b, side_tex_cood);

    double pts_outer_c[4][3] = {{-3, 0, 3},
                                {-3, 2, 3},
                                {3, 2, 3},
                                {3, 0, 3}};
    drawQuadFace("outlet_snow", pts_outer_c, side_tex_cood);

    double pts_outer_d[4][3] = {{-3, 0, -3},
                                {-3, 2, -3},
                                {3, 2, -3},
                                {3, 0, -3}};
    drawQuadFace("outlet_stone", pts_outer_d, side_tex_cood);

    double pts_bottom[4][3] = {{-3, 1.99, 3}, // avoid z-conflict
                                {3, 1.99, 3},
                                {3, 1.99, -3},
                                {-3, 1.99, -3}};
    drawQuadFace("outlet_bottom", pts_bottom, side_tex_cood);

    glPopMatrix();
}

void Scene::drawStation(int pos_x, int pos_y, int pos_z, bool status){
    glPushMatrix();
    glTranslatef(pos_x, pos_y, pos_z+1);
    drawQuad("dest_b_s", "dest_b_s", "dest_b_s", "dest_b_s", "dest_b_u", "dest_b_u", 1, 1);
    string tex_top;
    glTranslatef(0, 0, 6.0f);
    if(status == true) tex_top = "dest_a_yes";
    else tex_top = "dest_a_no";
    drawQuad("dest_a_s", "dest_a_s", "dest_a_s", "dest_a_s", tex_top, "dest_a_d", 1, 1);

    glPopMatrix();

    glPushMatrix();
    glScalef(5, 5, 5);
    glTranslatef(0, 0, 1.0f);
    glRotatef(90, 1, 0, 0);
    testscene.Draw();
    glPopMatrix();
}

void Scene::drawBelt(double proc){
    double roll_dist = proc / 250;
    glPushMatrix();
    double div_length = 0.01;
    double radius = 0.2;
    double div_angle = div_length / radius;
    for(int i = 0;i < 2.0f/div_length;i++){
        double pts_cood[4][3] = {{-1+div_length*i, 1, 1},
                                {-1+div_length*i, -1, 1},
                                {-1+div_length*(i+1), -1, 1},
                                {-1+div_length*(i+1), 1, 1}};
        double tex_cood[4][2] = {{roll_dist+div_length*i, 1},
                                {roll_dist+div_length*i, 0},
                                {roll_dist+div_length*(i+1), 0},
                                {roll_dist+div_length*(i+1), 1}};
        drawQuadFace("conv_belt", pts_cood, tex_cood);
    }
    for(double angle = 0;angle < PI;angle += div_angle){
        double pts_cood[4][3] = {{1.0f+radius*sin(angle), 1, (1-radius)+radius*cos(angle)},
                                {1.0f+radius*sin(angle), -1, (1-radius)+radius*cos(angle)},
                                {1.0f+radius*sin(angle+div_angle), -1, (1-radius)+radius*cos(angle+div_angle)},
                                {1.0f+radius*sin(angle+div_angle), 1, (1-radius)+radius*cos(angle+div_angle)}};
        double tex_cood[4][2] = {{roll_dist+radius*angle, 1},
                                {roll_dist+radius*angle, 0},
                                {roll_dist+radius*(angle+div_angle), 0},
                                {roll_dist+radius*(angle+div_angle), 1}};
        drawQuadFace("conv_belt", pts_cood, tex_cood);
    }
    for(int i = 0;i < 2.0f/div_length;i++){
        double pts_cood[4][3] = {{-1+div_length*i, 1, 1-0.2*2},
                                {-1+div_length*i, -1, 1-0.2*2},
                                {-1+div_length*(i+1), -1, 1-0.2*2},
                                {-1+div_length*(i+1), 1, 1-0.2*2}};
        double tex_cood[4][2] = {{1+roll_dist-div_length*i, 1},
                                {1+roll_dist-div_length*i, 0},
                                {1+roll_dist-div_length*(i+1), 0},
                                {1+roll_dist-div_length*(i+1), 1}};
        drawQuadFace("conv_belt", pts_cood, tex_cood);
    }
    for(double angle = 0;angle < PI;angle += div_angle){
        double pts_cood[4][3] = {{-1.0f-radius*sin(angle), 1, (1-radius)+radius*cos(angle)},
                                {-1.0f-radius*sin(angle), -1, (1-radius)+radius*cos(angle)},
                                {-1.0f-radius*sin(angle+div_angle), -1, (1-radius)+radius*cos(angle+div_angle)},
                                {-1.0f-radius*sin(angle+div_angle), 1, (1-radius)+radius*cos(angle+div_angle)}};
        double tex_cood[4][2] = {{1+roll_dist-radius*angle, 1},
                                {1+roll_dist-radius*angle, 0},
                                {1+roll_dist-radius*(angle+div_angle), 0},
                                {1+roll_dist-radius*(angle+div_angle), 1}};
        drawQuadFace("conv_belt", pts_cood, tex_cood);
    }
    glPopMatrix();
}

void Scene::drawConveyor(int pos_x, int pos_y, int pos_z, int dir, double proc){
    glPushMatrix();
    glTranslatef(pos_x, pos_y, pos_z+1);
    glRotatef(dir*90.0, 0, 0, 1);

    glPushMatrix();
    glScalef(0.8f, 0.85f, 1.0f);
    drawBelt(proc);
    glPopMatrix();

    glPushMatrix();
    glTranslatef(0, 0, -2/4.0f);
    glScalef(1.0f, 1.0f, 0.5f);
    drawQuad("conv_side", "conv_side", "conv_side", "conv_side", "conv_down", "conv_down", 1, 1);
    glPopMatrix();

    glPushMatrix();
    glTranslatef(0, -(2/2.0f-0.05f/2.0f), 0);
    glScalef(1.0f, 0.05f, 1.0f);
    drawQuad("conv_side", "conv_side", "conv_arrow", "conv_side", "conv_down", "conv_down", 1, 1);
    glPopMatrix();

    glPushMatrix();
    glTranslatef(0, (2/2.0f-0.05f/2.0f), 0);
    glScalef(1.0f, 0.05f, 1.0f);
    drawQuad("conv_side", "conv_side", "conv_side", "conv_arrow", "conv_down", "conv_down", 1, 1);
    glPopMatrix();

    glPushMatrix();
    GLUquadricObj *quad_obj = gluNewQuadric();
    gluQuadricDrawStyle(quad_obj, GLU_FILL);
    gluQuadricTexture(quad_obj, true);

    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
	glEnable(GL_TEXTURE_2D);
	textures.bindTexture("conv_drum");
    glPushMatrix();
    glTranslatef(-2/3.0f, (2-0.2)/2, (2-0.2f)-(2/2.0f));
    glRotatef(-proc, 0, 1, 0);
    glRotatef(90.0f, 1, 0, 0);
    gluCylinder(quad_obj, 0.2, 0.2, 2-0.2, 50, 50);
    glPopMatrix();

    glPushMatrix();
    glTranslatef(0, (2-0.2)/2, (2-0.2f)-(2/2.0f));
    glRotatef(-proc, 0, 1, 0);
    glRotatef(90.0f, 1, 0, 0);
    gluCylinder(quad_obj, 0.2, 0.2, 2-0.2, 50, 50);
    glPopMatrix();

    glPushMatrix();
    glTranslatef(2/3.0f, (2-0.2)/2, (2-0.2f)-(2/2.0f));
    glRotatef(-proc, 0, 1, 0);
    glRotatef(90.0f, 1, 0, 0);
    gluCylinder(quad_obj, 0.2, 0.2, 2-0.2, 50, 50);
    glPopMatrix();
    glDisable(GL_TEXTURE_2D);
    gluDeleteQuadric(quad_obj);
    glPopMatrix();

    glPopMatrix();
}

void Scene::drawBox(int box_type, double pos_x, double pos_y, double pos_z){
    string box_tex;
    glPushMatrix();
    glTranslatef(pos_x, pos_y, pos_z+1);
    if(box_type == 0) box_tex = "box_a";
    else if(box_type == 1) box_tex = "box_b";
    else box_tex = "box_c";
    drawQuad(box_tex, box_tex, box_tex, box_tex, box_tex, box_tex, 1 ,1);
    glPopMatrix();
}

void Scene::drawQuadFace(string tex, double pts[4][3], double tex_cood[4][2]){
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
	glEnable(GL_TEXTURE_2D);
	textures.bindTexture(tex);
    glBegin(GL_QUADS);
	glTexCoord2f(tex_cood[0][0], tex_cood[0][1]); glVertex3f(pts[0][0], pts[0][1], pts[0][2]);
	glTexCoord2f(tex_cood[1][0], tex_cood[1][1]); glVertex3f(pts[1][0], pts[1][1], pts[1][2]);
	glTexCoord2f(tex_cood[2][0], tex_cood[2][1]); glVertex3f(pts[2][0], pts[2][1], pts[2][2]);
	glTexCoord2f(tex_cood[3][0], tex_cood[3][1]); glVertex3f(pts[3][0], pts[3][1], pts[3][2]);
    glEnd();
    glDisable(GL_TEXTURE_2D);
}

void Scene::drawQuad(string tex_left, string tex_right, string tex_front, string tex_back,
                    string tex_up, string tex_down, double tex_repeat_x, double tex_repeat_y){
    double face_up[4][3] = {{-1, 1, 1}, {-1, -1, 1}, {1, -1, 1}, {1, 1, 1}};
    double face_down[4][3] = {{-1, 1, -1}, {-1, -1, -1}, {1, -1, -1}, {1, 1, -1}};
    double face_right[4][3] = {{1, -1, 1}, {1, -1, -1}, {1, 1, -1}, {1, 1, 1}};
    double face_left[4][3] = {{-1, -1, 1}, {-1, -1, -1}, {-1, 1, -1}, {-1, 1, 1}};
    double face_back[4][3] = {{-1, 1, 1}, {-1, 1, -1}, {1, 1, -1}, {1, 1, 1}};
    double face_front[4][3] = {{-1, -1, 1}, {-1, -1, -1}, {1, -1, -1}, {1, -1, 1}};

    double tex_cood[4][2] = {{tex_repeat_x, tex_repeat_y},
                            {tex_repeat_x, 0},
                            {0, 0},
                            {0, tex_repeat_y}};

    drawQuadFace(tex_up, face_up, tex_cood);
    drawQuadFace(tex_down, face_down, tex_cood);
    drawQuadFace(tex_right, face_right, tex_cood);
    drawQuadFace(tex_left, face_left, tex_cood);
    drawQuadFace(tex_back, face_back, tex_cood);
    drawQuadFace(tex_front, face_front, tex_cood);
}

void Scene::drawPlatform(int size){
    glPushMatrix(); // draw skybox
    glScalef(200, 200, 200);
    drawQuad("sky_l", "sky_r", "sky_b", "sky_f", "sky_d", "sky_u", 1, 1);
    glPopMatrix();

    glPushMatrix();
    glTranslatef(0, 0, -size);
    glScalef(size, size, size);
    drawQuad("wall_s", "wall_s", "wall_s", "wall_s", "wall_t", "wall_t", size/20.0f, size/20.0f);
    glPopMatrix();

    glPushMatrix();
    glTranslatef(-size/2.0f, size*2.0f-size/2.0f, size/4.0f);
    glScalef(size, size, size);
    drawQuad("wall_s", "wall_s", "wall_s", "wall_s", "wall_t", "wall_t", size/20.0f, size/20.0f);
    glPopMatrix();

}

void Scene::initDraw(void){
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(eye[0], eye[1], eye[2], center[0], center[1], center[2], 0, 1, 0);
}

void Scene::setRender(void){
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    glEnable(GL_DEPTH_TEST);
}

bool Scene::checkSucceed(void){
    bool all_succeed = true;
    for(vector<Station>::size_type j = 0; j < station_list.size(); j++)
        all_succeed &= station_list[j].checkResult();
    if(all_succeed){
        is_running = false;
        is_succeed = true;
    }
    return all_succeed;
}

bool Scene::checkArrived(int box_index){
    vector<double> pos_box = box_list[box_index].getPosition();
    for(vector<Station>::size_type j = 0; j < station_list.size(); j++){
        vector<double> pos_station = station_list[j].getPosition();
        bool on_station = box_list[box_index].getType() == station_list[j].getID();
        on_station &= abs(pos_box[0]-pos_station[0]) < EPS;
        on_station &= abs(pos_box[1]-pos_station[1]) < EPS;
        on_station &= pos_box[2]-(pos_station[2]+2) < EPS;
        if(on_station){
            station_list[j].finish(true);
            return true;
        }
    }
    return false;
}

bool Scene::procMoving(int box_index){
    vector<double> pos_box = box_list[box_index].getPosition();
    for(vector<Conveyor>::size_type j = 0; j < conveyor_list.size(); j++){
        vector<double> pos_conveyor = conveyor_list[j].getPosition();
        int dir_conveyor = conveyor_list[j].getDirection();
        if(dir_conveyor == 1 || dir_conveyor == 3){
            if(abs(pos_conveyor[1]-pos_box[1]) >= 2) continue;
        }else{
            if(abs(pos_conveyor[0]-pos_box[0]) >= 2) continue;
        }
        if(pos_box[2]-(pos_conveyor[2]+2) < EPS){
            if(dir_conveyor == 0 && (pos_box[1]-pos_conveyor[1]) < EPS){
                box_list[box_index].setPosition(pos_box[0]-MOVE_SPEED,pos_box[1],pos_box[2]);
                return true;
            }else if(dir_conveyor == 1 && (pos_box[0]-pos_conveyor[0]) < EPS){
                box_list[box_index].setPosition(pos_box[0],pos_box[1]-MOVE_SPEED,pos_box[2]);
                return true;
            }else if(dir_conveyor == 2 && (pos_box[1]-pos_conveyor[1]) < EPS){
                box_list[box_index].setPosition(pos_box[0]+MOVE_SPEED,pos_box[1],pos_box[2]);
                return true;
            }else if(pos_box[1] == pos_conveyor[1] && (pos_box[0]-pos_conveyor[0]) < EPS){
                box_list[box_index].setPosition(pos_box[0],pos_box[1]+MOVE_SPEED,pos_box[2]);
                return true;
            }
        }
    }
    return false;
}

bool Scene::procDrop(int box_index){
    vector<double> pos_box = box_list[box_index].getPosition();
    if(pos_box[2] > 0){
        box_list[box_index].setPosition(pos_box[0],pos_box[1],pos_box[2]-DROP_SPEED);
        return true;
    }else return false;
}

void Scene::step(void){
    if(checkSucceed()) return;
    for(vector<Box>::size_type i = 0; i < box_list.size(); i++){
        if(checkArrived(i)) continue;
        else if(procMoving(i)) continue;
        else if(!procDrop(i)){
            is_running = false;
            is_succeed = false;
            for(vector<Station>::size_type j = 0; j < station_list.size(); j++){
                if(station_list[j].checkStatus() == true)
                    station_list[j].finish(false);
            }
            return;
        }
    }
}

void Scene::addConveyor(int x, int y, int z, int dir){
    Conveyor new_convoyer(x, y, z, dir);
    conveyor_list.push_back(new_convoyer);
}

void Scene::abort(void){
    if(!is_running) return;
    is_running = false;
}

void Scene::reset(void){
    if(is_running) return;
    is_running = false;
    is_ready = true;
    is_succeed = false;
    for(vector<Station>::size_type i = 0; i < station_list.size(); i++){
        station_list[i].restart();
        station_list[i].finish(false);
    }
}

void Scene::start(void){
    if(is_running || !is_ready) return;
    is_running = true;
    is_ready = false;
    for(vector<Station>::size_type i = 0; i < station_list.size(); i++)
        station_list[i].restart();
}

void Scene::draw(){
    initDraw();
    setRender();
    setLight();
    glRotatef(-90, 1, 0, 0);
    drawPlatform(25);
    drawOutlet(4, 10, 16);
    drawOutlet(-4, 10, 16);
    drawOutlet(-12, 10, 16);
    if(is_ready){ // show hints
        drawBox(2, 4, 13, 8);
        drawBox(1, -4, 13, 8);
        drawBox(0, -12, 13, 8);
        drawBox(0, 18, 15, 2);
        drawBox(1, -4, -20, 2);
        drawBox(2, -12, -20, 2);
    }
    for(vector<Station>::size_type i = 0; i < station_list.size(); i++){
        vector<double> pos = station_list[i].getPosition();
        bool color = station_list[i].getColor();
        drawStation(pos[0], pos[1], pos[2], color);
        if(station_list[i].checkStatus())
            station_list[i].animate(ANIMATION_SPEED);
    }
    for(vector<Conveyor>::size_type i = 0; i < conveyor_list.size(); i++){
        vector<double> pos = conveyor_list[i].getPosition();
        int dir = conveyor_list[i].getDirection();
        double proc = conveyor_list[i].getProcess();
        drawConveyor(pos[0], pos[1], pos[2], dir, proc);
        if(is_running) conveyor_list[i].animate(ANIMATION_SPEED);
    }
    for(vector<Box>::size_type i = 0; i < box_list.size(); i++){
        vector<double> pos = box_list[i].getPosition();
        int type = box_list[i].getType();
        drawBox(type, pos[0], pos[1], pos[2]);
    }
    if(is_running) step();
}

void redrawCallback(void){
    static Scene game_scene;
    game_scene.draw();
    glutSwapBuffers();
}
